home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpat2-1.000 / xpat2-1 / xpat2-1.04 / src / loadsave.c < prev    next >
C/C++ Source or Header  |  1995-10-14  |  10KB  |  329 lines

  1. /*****************************************************************************/
  2. /*                                         */
  3. /*                                         */
  4. /*    X patience version 2 -- module loadsave.c                 */
  5. /*                                         */
  6. /*    Functions for game logging and loading/saving games.             */
  7. /*    written by Heiko Eissfeldt and Michael Bischoff                 */
  8. /*    see COPYRIGHT.xpat2 for Copyright details                 */
  9. /*                                         */
  10. /*    24-Feb-1993: First release (0.1)                     */
  11. /*    19-Mar-1993: POSIX.1 now optional                     */
  12. /*    24-Mar-1993: changed filename "log" to "xpat.log"             */
  13. /*                                         */
  14. /*                                         */
  15. /*****************************************************************************/
  16. #include "xpatgame.h"
  17.  
  18. #define NARGS    32    /* twice the size of xpat 1 */
  19. #define BUFSIZE    32    /* at least length of longest shortname + 1 */
  20.  
  21. #define MAGIC1    0x7419    /* magic of xpat version 1 */
  22. #define MAGIC2    0x741a    /* magic of xpat version 2 */
  23.  
  24. #include <limits.h>
  25.  
  26. #ifndef _POSIX_NAME_MAX
  27. #  undef _POSIX_SOURCE        /* seems that we have no POSIX system! */
  28. #  define NAME_MAX    14    /* every UNIX should have at least this */
  29. #else
  30. #  include <unistd.h>        /* for pathconf() */
  31. #  include <sys/utsname.h>    /* for uname() */
  32. #endif
  33.  
  34. #include <time.h>
  35. #include "version.h"
  36.  
  37.  
  38. /* code to switch between real and effective user id */
  39. /* we must use the real user id when saving files */
  40.  
  41. void switch_uid(int to_real) {
  42. #ifdef _POSIX_SAVED_IDS
  43.     static int uid_state = -1; /* -1 = unknown, 1 = real, 0 = effective */
  44.     static uid_t real_uid, effective_uid;
  45.     if (uid_state < 0) {
  46.     real_uid = getuid();
  47.     effective_uid = geteuid();
  48.     uid_state = 0;
  49.     }
  50.     if (to_real != uid_state && real_uid != effective_uid) {
  51.     setuid(to_real ? real_uid : effective_uid);
  52.     uid_state = to_real;
  53.     }
  54. #endif
  55. }
  56.  
  57. static void read_err(const char *msg) {
  58.     if (game.graphic) {
  59.     show_message("%s %s", TXT_LOAD_ERR_BASIC, msg);
  60.     cmd_LeavePat();                        /* make it better! */
  61.     }
  62.     fprintf(stderr, "%s %s\n", TXT_LOAD_ERR_BASIC, msg);
  63.     exit(EXIT_FAILURE);
  64. }
  65.  
  66. static void portable_to_internal(long *args, unsigned char *p, int num) {
  67.     do {
  68.     int j;
  69.     *args = 0;
  70.     for (j = 0; j < 4; ++j)
  71.         *args += (long)p[3-j] << (j << 3);
  72.     ++args;
  73.     p += 4;
  74.     } while (--num);
  75. }
  76.  
  77. static void internal_to_portable(unsigned char *p, long *args, int num) {
  78.     do {
  79.     int j;
  80.     memset(p, (*args < 0 ? -1 : 0), 4);
  81.     for (j = 0; j < 4; ++j)
  82.         p[3-j] = (unsigned char)(*args >> (j << 3));
  83.     ++args;
  84.     p += 4;
  85.     } while (--num);
  86. }
  87.  
  88. void load_game(const char *file) {
  89.     FILE *fp;
  90.     char buffer[BUFSIZE];
  91.     long args[NARGS];
  92.     int i;
  93.     unsigned char p[NARGS * 4];
  94.  
  95.     if (!(fp = fopen(file, "rb")))
  96.     read_err(TXT_LOAD_ERR_OPEN);
  97.     if (fread(buffer, 1, BUFSIZE, fp) != BUFSIZE ||
  98.     fread(p, 4, 16, fp) != 16)
  99.     read_err(TXT_LOAD_ERR_HEADER);
  100.     portable_to_internal(args, p, 16);
  101.  
  102.     switch ((int)args[15]) {
  103.     case MAGIC1:    /* read xpat version 1 game.file */
  104.     for (i = 16; i < NARGS; ++i)    /* no further game.*/
  105.         args[i] = -1;
  106.     break;
  107.     case MAGIC2:    /* must read extended header */
  108.     if (fread(p, 4, NARGS-16, fp) != NARGS-16)
  109.         read_err(TXT_LOAD_ERR_HEADER);
  110.     portable_to_internal(args+16, p, NARGS-16);
  111.     break;
  112.     default:
  113.     read_err(TXT_LOAD_ERR_BADMAGIC);
  114.     }
  115.     new_rules(buffer, args[0], args[1], args[2], args[3], args[4], args[18], args[19], args[5], args[6], args[7]);
  116.     if (game.numalloc < args[9]) {
  117.     if (game.numalloc)
  118.         free(game.move);
  119.     memo_alloc((args[9]|15)+1);
  120.     }
  121.     newgame(args[8]);
  122.     game.stored_moves = args[9];
  123.     game.finished = args[12];
  124.     for (i = 0; i < game.stored_moves; i += 16) {
  125.     if (fread(p, 4, 16, fp) != 16) {
  126.         read_err(TXT_LOAD_ERR_MOVES);
  127.         break;
  128.     }
  129.     portable_to_internal((long *)(game.move+i), p, 16);
  130.     }
  131.     fclose(fp);
  132.     if (args[15] == MAGIC1)
  133.     /* convert moves to version 2 */
  134.     for (i = 0; i < game.stored_moves; ++i)
  135.         if ((game.move[i] & SPECIAL_MASK) != NEW_CARDS_MOVE)
  136.         /* reset MOVE_TURNED flag in the upper part */
  137.         game.move[i] &= 0x7fffffffUL;
  138.     ++game.savecount;
  139.     game.bookmark = args[10];        /* preset bookmark to load point */
  140.     if (game.graphic) {
  141.     graphics_control(Disable);
  142.     cmd_GotoBookmark();
  143.     graphics_control(Enable);
  144.     refresh_screen();        /* draw complete screen */
  145.     } else
  146.     cmd_GotoBookmark();        /* graphics disabled anyway */
  147.     assert(game.move_ptr == args[10]);
  148.     assert(game.counter[1] == args[13]);    /* same for 2..4 */
  149.     game.cheat_count = args[11];
  150. }
  151.  
  152.  
  153. void save_game(const char *file) {
  154.     FILE *fp;
  155.     char buffer[32];
  156.     char filename[64];    /* must be 15 at least */
  157.     long args[24];
  158.     int i;
  159.     unsigned char p[4 * 24];
  160.  
  161.     if (!file) {
  162.     /* compute the filename to use */
  163.     long name_max;
  164.  
  165. #ifdef NAME_MAX    
  166.     name_max = NAME_MAX;
  167. #else
  168.     if ((name_max = pathconf(".", _PC_NAME_MAX)) == -1L)
  169.         name_max = _POSIX_NAME_MAX;    /* error => use 14 chars */
  170. #endif
  171.     if (name_max >= sizeof(filename))
  172.         name_max = sizeof(filename) - 1;
  173.     /* copy characters to the filename string */
  174.     /* POSIX allows digits, letters, '.', '-', '_' */
  175.     {   char *wr; const char *rd;
  176.         rd = rules.shortname;
  177.         for (wr = filename; *rd && wr - filename <= name_max - 10; ++rd)
  178.         if (isalnum(0xff & *rd) || *rd == '-')
  179.             *wr++ = *rd;
  180.         sprintf(wr, ".%09ld", game.seed);
  181.     }
  182.     file = filename;
  183.     }
  184.  
  185.     switch_uid(1);    /* saves in users home directory */
  186.     if (!(fp = fopen(file, "wb"))) {
  187.     show_message("%s %s", TXT_SAVE_ERR_BASIC, TXT_SAVE_ERR_OPEN);
  188.     goto werr2;
  189.     }
  190.     strcpy(buffer, rules.shortname);
  191.     for (i = 0; i < NARGS; ++i)
  192.     args[i] = -1;
  193.     if (rules.customized & CUSTOM_DECKS)
  194.     args[0] = rules.numdecks;
  195.     if (rules.customized & CUSTOM_SLOTS)
  196.     args[1] = rules.numslots;
  197.     if (rules.customized & CUSTOM_FACEUP)
  198.     args[2] = rules.faceup;
  199.     if (rules.customized & CUSTOM_FACEDOWN)
  200.     args[3] = rules.facedown;
  201.     if (rules.customized & CUSTOM_JOKERS)
  202.     args[4] = rules.numjokers;
  203.     if (rules.customized & CUSTOM_TMPS)
  204.     args[18] = rules.numtmps;
  205.     if (rules.customized & CUSTOM_PARAM0)
  206.     args[19] = rules.param[0];
  207.     if (rules.customized & CUSTOM_PARAM1)
  208.     args[5] = rules.param[1];
  209.     if (rules.customized & CUSTOM_PARAM2)
  210.     args[6] = rules.param[2];
  211.     if (rules.customized & CUSTOM_PARAM3)
  212.     args[7] = rules.param[3];
  213.     args[ 8] = game.seed;
  214.     args[ 9] = game.stored_moves;
  215.     args[10] = game.move_ptr;
  216.     args[11] = game.cheat_count;
  217.     args[12] = game.finished;
  218.     args[13] = game.counter[1];
  219.     args[14] = game.counter[2];
  220.     args[15] = MAGIC2;
  221.     args[16] = game.counter[3];
  222.     args[17] = game.counter[0];
  223.     internal_to_portable(p, args, NARGS);
  224.     if (fwrite(buffer, 1, BUFSIZE, fp) != BUFSIZE ||
  225.     fwrite(p, 4, NARGS, fp) != NARGS) {
  226.     show_message("%s %s", TXT_SAVE_ERR_BASIC, TXT_SAVE_ERR_HEADER);
  227.     goto werr;
  228.     }
  229.     for (i = 0; i < game.stored_moves; i += 16) {
  230.     internal_to_portable(p, (long *)(game.move+i), 16);
  231.     if (fwrite(p, 4, 16, fp) != 16) {
  232.         show_message("%s %s", TXT_SAVE_ERR_BASIC, TXT_SAVE_ERR_MOVES);
  233.         goto werr;
  234.     }
  235.     }
  236.     fclose(fp);
  237.     switch_uid(0);
  238.     show_message(TXT_SAVE_OK);
  239.     play_sound("ok");    /* found no sound file for this. maybe later */
  240.     return;
  241.  
  242. werr:
  243.     fclose(fp);
  244. werr2:
  245.     switch_uid(0);
  246.     play_sound("cannotsave");
  247. }
  248.  
  249. void write_log_file(void) {
  250.     time_t t;
  251.     FILE *fp;
  252.  
  253. #ifdef _POSIX_SOURCE
  254.     struct utsname utsname;
  255.     const char *username;
  256. #endif
  257.  
  258.     t = time((time_t *)0);
  259.  
  260.     if (!(fp = fopen(SCOREFILE, "a"))) {
  261.     fprintf(stderr, "xpat: warning: cannot write to log file "
  262.         SCOREFILE "\n");
  263.     return;        /* cannot write to file */
  264.     }
  265.     fprintf(fp, "\n%s", ctime(&t));
  266.  
  267. #ifdef _POSIX_SOURCE
  268.     if ((username = getlogin()) != NULL
  269.     /* cuserid has been removed in the 1990 POSIX revision. */
  270.     /* Thus we make the following code optional (default: use it) */
  271. #ifndef NO_CUSERID
  272.         /* if started directly under a window-manager menu, getlogin()
  273.            returns NULL, so get username with cuserid() (ThMO) */
  274.     || (username = cuserid(NULL)) != NULL
  275. #endif
  276.     )
  277.     fprintf(fp, "  \"%s\"", username);
  278.     else
  279. #endif
  280.     fprintf(fp, "  someone");
  281.  
  282. #ifdef _POSIX_SOURCE
  283.     if (uname(&utsname) >= 0)
  284.     fprintf(fp, " on %s\n  running %s Version %s (%s)\n ",
  285.         utsname.nodename,
  286.         utsname.sysname, utsname.release, utsname.version);
  287. #endif
  288.  
  289.     fprintf(fp, " finished patience %s\n", rules.shortname);
  290.     if (rules.customized & CUSTOM_DECKS)
  291.     fprintf(fp, "  with %d decks\n", rules.numdecks);
  292.     if (rules.customized & CUSTOM_SLOTS)
  293.     fprintf(fp, "  with %d slots\n", rules.numslots);
  294.     if (rules.customized & CUSTOM_TMPS)
  295.     fprintf(fp, "  with %d tmps\n", rules.numtmps);
  296.     if (rules.customized & CUSTOM_FACEUP)
  297.     fprintf(fp, "  with %d cards faceup\n", rules.faceup);
  298.     if (rules.customized & CUSTOM_FACEDOWN)
  299.     fprintf(fp, "  with %d cards facedown\n", rules.facedown);
  300.     if (rules.customized & CUSTOM_JOKERS)
  301.     fprintf(fp, "  with %d jokers\n", rules.numjokers);
  302.  
  303.     if (rules.customized & CUSTOM_PARAM0)
  304.     fprintf(fp, "  param0 = %d\n", rules.param[0]);
  305.     if (rules.customized & CUSTOM_PARAM1)
  306.     fprintf(fp, "  param1 = %d\n", rules.param[1]);
  307.     if (rules.customized & CUSTOM_PARAM2)
  308.     fprintf(fp, "  param2 = %d\n", rules.param[2]);
  309.     if (rules.customized & CUSTOM_PARAM3)
  310.     fprintf(fp, "  param3 = %d\n", rules.param[3]);
  311.     if (game.counter[0])
  312.     fprintf(fp, "  counter0 = %d\n", game.counter[0]);
  313.     if (game.counter[1])
  314.     fprintf(fp, "  counter1 = %d\n", game.counter[1]);
  315.     if (game.counter[2])
  316.     fprintf(fp, "  counter2 = %d\n", game.counter[2]);
  317.     if (game.counter[3])
  318.     fprintf(fp, "  counter3 = %d\n", game.counter[3]);
  319.  
  320.  
  321.     fprintf(fp, "  using xpat2 version %s, game seed %9ld with %d moves\n",
  322.         VERSION, game.seed, game.n_moves);
  323.     if (game.cheat_count)
  324.     fprintf(fp, "  and cheatet! (count = %d)\n", game.cheat_count);
  325.     else
  326.     fprintf(fp, "  in a truly noble manner!\n");
  327.     fclose(fp);
  328. }
  329.